/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = main.c                                             */
/*  NOTE      = 整体入口                                           */
/*  DATE      = 2014/10/08 by yaohl                                */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <sys/prctl.h>

#include <libxml/xpath.h>
#include <libxml/parser.h>

#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/thread.h>

#include <daq.h>
#include <nids.h>

//#include <pcap/pcap.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frhash2.h"
#include "frstr.h"

#include "frdaq.h"
#include "conntrack.h"
#include "module.h"
#include "frtimer.h"

#include "frame_params.h"
#include "fruser_def.h"
#include "frversion.h"
#include "frame.h"
#include "frct_mng.h"
#include "frct_hash.h"
#include "frct_expect.h"
#include "frct_expect2.h"
#include "frservice_mng.h"
#include "frreport_session_mng.h"
#include "frtask_mng.h"
#include "frmodule_mng.h"
#include "frproto_mng.h"
#include "frproto_l7default.h"
#include "frtask_do.h"
#include "frfilter.h"
#include "frlua_config.h"
#include "frssl_config.h"
#include "client.pb-c.h"
#include "frcmd_server.h"
#include "frcmd_server_l7.h"
#include "frreport_mng.h"
#include "frstat_module.h"
#include "frstat_system.h"
#include "frstat_l4.h"
#include "frstat_thread.h"
#include "frstat_server.h"
#include "frstat_conn.h"
#include "frstat_port.h"
#include "frstat_pkg.h"
#include "frlua_config.h"
#include "frct_ssl_mng.h"
#include "frcmd_http.h"

typedef struct __apm_report_params {
    int i_totools;
    int i_tofile;
    int i_console;
    int i_base64;
}Frreport_params;

typedef struct __st_packet_count {
    unsigned long ul_pkg_rcv;
    unsigned long ul_pkg_drop;
} frPacketCnt;

/* 程序运行标识 */
int g_i_flag_run =1;
int g_i_task_chk_timer=FR_NO; /* 用于判断 g_thread_id_do_timer 线程是否在运行*/

void *g_p_memstat=NULL;

FR_STATIC int g_i_flag_nids_init=FR_NO;
FR_STATIC int g_i_pcap_wait = 3; //程序启动等待数据包进入时间(秒),默认 3sec
FR_STATIC int g_i_exit_wait = 5; //使用pcap测试时,程序等待退出时间sec
FR_STATIC int g_i_use_system_time = 0; //1:使用系统时间更新数据包(从pcap文件读取时有效)

/* event_base */
struct event_base *g_p_st_ebase = NULL;
FR_STATIC pthread_t g_thread_id_cmd_line=0;
FR_STATIC pthread_t g_thread_id_do_timer=0;
FR_STATIC pthread_t g_thread_udp_drop = 0;

/* 任务处理线程个数  */
FR_STATIC int g_i_do_task_cnt=1;
FR_STATIC pthread_t *g_p_thread_id_do_task=NULL;

/* 统计线程个数  */
#define APM_STAT_CNT    7
FR_STATIC pthread_t g_thread_id_stat[APM_STAT_CNT];

FR_STATIC pthread_t g_thread_id_chk_dump=0;
/* 上报线程 */
FR_STATIC pthread_t g_thread_id_report=0;
/* 从上报信息中统计连接数 */
FR_STATIC pthread_t g_thread_id_stat_conn=0;
/* 接收ssl解析后的数据 */
FR_STATIC pthread_t g_thread_ct_ssl_mng = 0;
/* 关联连接处理 */
FR_STATIC pthread_t g_thread_id_chk_exp=0;
FR_STATIC pthread_t g_thread_id_chk_report_session=0;
FR_STATIC pthread_t g_thread_id_http_srv=0;
/* lua配置信息处理 */
FR_STATIC pthread_t g_thread_id_chk_lua=0;
/* 接收数据包 */
int g_i_nids_threads = 1;
int g_i_pcap_threads = 1;
FR_STATIC pthread_t g_thread_id_pcap[APM_DEV_MAX];
FR_STATIC pthread_t g_thread_nids[APM_DEV_MAX];
Frlist_header g_st_lst_head_dev;
struct nids_ip_tcp_stream g_st_nids_ip_tcp_stream[APM_DEV_MAX];

FR_STATIC unsigned int g_ui_threads=1;  //总线程个数(包括主线程)
FR_STATIC int g_i_enable_stat_tcp=0;    //tcp统计上报控制

#define APM_STAT_ERVER_CHECK_TIME       600
#define APM_STAT_RELATED_CHECK_TIME     600

extern unsigned long g_ul_ct_used;
extern unsigned long g_ul_pcap_queue_used;

FR_STATIC Frexp_ref g_st_expRef={NULL, NULL};
FR_STATIC Frexp_ref g_st_exp2Ref={NULL, NULL};
FR_STATIC Frservice_ref g_st_serviceRef={NULL, NULL};
FR_STATIC Frreport_session_ref g_st_report_session_Ref={NULL, NULL, NULL};
FR_STATIC Report_module g_st_report_moduleRef = {NULL, NULL, NULL, NULL, NULL};

FR_STATIC Frmemstat_mng g_st_memstat_mng={0,FR_MEMSTAT_COUNT_MAX};
FR_STATIC pthread_rwlock_t  g_memstat_rwlock = PTHREAD_RWLOCK_INITIALIZER;
FR_STATIC Frmem_env g_st_mem_env = {&g_st_memstat_mng, &g_memstat_rwlock};

ApmContext g_st_apm_context = {&g_st_expRef, &g_st_exp2Ref, &g_st_serviceRef, &g_st_report_session_Ref, &g_st_report_moduleRef, &g_st_mem_env};

FR_STATIC int g_flag_dump_file=0;
FR_STATIC struct timeval g_st_timestamp_pkg_upd={0,0};
FR_STATIC int g_flag_drop_timestamp_incorrect =0;

FR_STATIC void __frame_devs_node_free(Frlist_node* node);

/*******************************************************************************
*  FUNC     :  获取线程数
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
unsigned int frame_threads_cnt(void)
{
    return g_ui_threads;
}

//主框架版本号
FR_STATIC char g_arr_frame_version[30];

/*******************************************************************************
*  FUNC     :  统计模块初始化
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_stat_init(void)
{
    frstat_module_init(1);
    frstat_system_init(1);
    frstat_l4_init();
    frstat_thread_init(1);
    frstat_server_init(1);
    frstat_pkg_init();
    return;
}

/*******************************************************************************
*  FUNC     :  统计模块释放
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_stat_destory(void)
{
    frstat_pkg_destory();
    frstat_server_destory();
    frstat_thread_destory();
    frstat_l4_destroy();
    frstat_system_destroy();
    frstat_module_destory();

    return;
}

/*******************************************************************************
*  FUNC     :  模块信息统计
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_module(void *arg)
{
    struct timeval st_time_start,st_time_end, st_delay;
    long l_time_diff=0;

    prctl(PR_SET_NAME,"stat_module");
    do
    {
        gettimeofday(&st_time_start, NULL);

        frstat_module_bps();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 0)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  系统信息统计
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_system(void *arg)
{
    struct timeval st_time_start,st_time_end, st_delay;
    long l_time_diff=0;

    prctl(PR_SET_NAME,"stat_system");
    do
    {
        gettimeofday(&st_time_start, NULL);

        frstat_system_count();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 0)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  l4 tcp 信息统计
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_l4_tcp(void *arg)
{
    struct timeval st_time_start,st_time_end, st_delay;
    long l_time_diff=0;

    prctl(PR_SET_NAME,"stat_l4_tcp");

    while(g_i_flag_nids_init == FR_NO && g_i_flag_run)
        sleep(1);

    if(g_i_flag_nids_init == FR_NO)
        return (void*)NULL;

    do
    {
        gettimeofday(&st_time_start, NULL);

        if(g_i_enable_stat_tcp)
            frstat_l4_report();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 0)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  数据处理线程的相关信息统计
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_thread(void *arg)
{
    struct timeval st_time_start,st_time_end , st_delay;
    long l_time_diff=0;

    prctl(PR_SET_NAME,"stat_thread");
    do
    {
        gettimeofday(&st_time_start, NULL);

        frstat_thread_count();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 0)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  数据处理线程的相关信息统计
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_server(void *arg)
{
    struct timeval st_time_start,st_time_end , st_delay;
    long l_time_diff=0, l_count=0;

    prctl(PR_SET_NAME,"stat_server");
    do
    {
        gettimeofday(&st_time_start, NULL);

        frstat_server_count();

        if(l_count++ % 60 == 0)
        {
            l_count = 0;
            frstat_server_check_timeouts(APM_STAT_ERVER_CHECK_TIME);
            frstat_related_check_timeouts(APM_STAT_RELATED_CHECK_TIME);
        }

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 0)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  统计网卡和libpcap收包信息
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_packet_if_pcap(void)
{
    int i_has_dev = 0;
    Frlist_node *p_st_node = NULL;

    if(g_i_flag_nids_init == FR_NO)
        return;

    p_st_node = FRLIST_FIRST_NODE(&g_st_lst_head_dev);
    while(p_st_node && p_st_node->data)
    {
        Nids_handle *p_nids_handle = NULL;

        p_nids_handle = (Nids_handle *)FRLIST_GET_NODE_DATA(p_st_node);
        if (p_nids_handle->p_daq_hand)
        {
            DAQ_Stats_t st_stat;
            if (DAQ_GetStats(p_nids_handle->p_daq_hand, &st_stat))
            {
                frstat_pkg_add_if_rcv(st_stat.hw_packets_received);
                frstat_pkg_add_if_drop(st_stat.hw_packets_dropped);
                //时间差的原因,存在 packets_received > hw_packets_received
                if(st_stat.hw_packets_received > st_stat.packets_received)
                    frstat_pkg_add_pcap_rcv(st_stat.packets_received);
                else
                    frstat_pkg_add_pcap_rcv(st_stat.hw_packets_received);
                i_has_dev = 1;
            }
        }

        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }
    if (!i_has_dev)
    {
        frstat_pkg_add_if_rcv(0);
        frstat_pkg_add_if_drop(0);
        frstat_pkg_add_pcap_rcv(0);
        //frstat_pkg_add_pcap_drop(0);
        return;
    }

    return;
}

/*******************************************************************************
*  FUNC     :  统计框架数据收到的各类数据
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_packet_rcv(void *arg)
{
    struct timeval st_time_start,st_time_end, st_delay;
    long l_time_diff=0;

    prctl(PR_SET_NAME,"stat_packet_rcv");
    do
    {
        __frame_packet_if_pcap();
        gettimeofday(&st_time_start, NULL);

        frstat_pkg_count();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 20)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}


/*******************************************************************************
*  FUNC     :  统计框架数据收到的各类数据
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_http_srv(void *arg)
{
    int i_socket_server = -1;
    int i_socket_client = -1;
    struct sockaddr_in client_name;
    socklen_t client_name_len = sizeof(client_name);
    char arr_buff[1024] = {0};

    /*在对应端口建立 httpd 服务*/
    i_socket_server = frcmd_http_startup(st_apm_params.us_port);
    if(i_socket_server > 0)
        FRLOG_INFO("httpd running on port %d", st_apm_params.us_port);
    else
    {
        FRLOG_ERROR_DETAIL("fail:httpd running on port %d", st_apm_params.us_port);
        while (g_i_flag_run)
        {
            sleep(1);
        }
        return (void*)NULL;
    }

    while (g_i_flag_run)
    {
        /*套接字收到客户端连接请求*/
        i_socket_client = accept(i_socket_server, (struct sockaddr *)&client_name, &client_name_len);
        if (i_socket_client == -1)
        {
            FRLOG_ERROR_DETAIL_TIME("accept failed");
            close(i_socket_server);
            usleep(10000);
            continue;
        }

        /* 处理新请求 */
        recv(i_socket_client, arr_buff, sizeof(arr_buff), 0);
        frcmd_http_frameInfo(i_socket_client);

        /*断开与客户端的连接（HTTP 特点：无连接）*/
        close(i_socket_client);
    }
    close(i_socket_server);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     : 清除过去的关联连接
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_clean_expect(void *arg)
{
    struct timeval st_time_start,st_time_end, st_delay;
    long l_time_diff=0;

    prctl(PR_SET_NAME,"chk_expect");
    do
    {
        gettimeofday(&st_time_start, NULL);

        frexpect_timeout_clean();
        frexpect2_timeout_clean();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(1000000 - l_time_diff > 20)
        {
            st_delay.tv_sec = (1000000 -l_time_diff) / 1000000;
            st_delay.tv_usec = (1000000 -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     : 清除过去的关联连接
*  ARGS     :
*  RTN      :
*  NOTE     : 2sec检查1次
*******************************************************************************/
FR_STATIC void *__frame_clean_report_session(void *arg)
{
    struct timeval st_time_start,st_time_end, st_delay;
    long l_time_diff=0, l_dela=2000000;//2sec

    prctl(PR_SET_NAME,"chk_report_session");
    do
    {
        gettimeofday(&st_time_start, NULL);

        frreport_session_mng_clean();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        if(l_dela - l_time_diff > 20)
        {
            st_delay.tv_sec = (l_dela -l_time_diff) / 1000000;
            st_delay.tv_usec = (l_dela -l_time_diff) % 1000000;
            select(0, NULL, NULL, NULL, &st_delay);
        }
    } while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     : 清除已经打上删除标识的lua配置
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_clean_lua_cfg(void *arg)
{
    int i_loop=0;

    prctl(PR_SET_NAME,"chk_lua_cfg");
    do
    {
        frlua_chk_del();

        //不需要很精确,大概延迟10秒
        for(i_loop=0; i_loop < 10; i_loop++)
        {
            if(g_i_flag_run == 0)
                break;
            sleep(1);
        }

    }while(g_i_flag_run);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  更改nids解析时，是否检查checksum
*  ARGS     :  i_flag_enable      (FR_YES:设定checksum有效; FR_NO:设定checksum无效)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_chg_chksum(int i_flag_enable)
{
    FR_STATIC struct nids_chksum_ctl ctl;

    ctl.netaddr = 0;
    ctl.mask = 0;

    //check sum 有效
    if(i_flag_enable == FR_YES)
    {
        ctl.action = NIDS_DO_CHKSUM;
        nids_register_chksum_ctl(&ctl, 0); //enable checksum verification
    }
    else
    {
        ctl.action = NIDS_DONT_CHKSUM;
        nids_register_chksum_ctl(&ctl, 1); //disable checksum verification
    }

    return;
}

#ifdef FRFRAME_DO_UDP
FR_STATIC void __frame_udp_callback(struct tuple4 *addr, char *buf, int len, struct ip *iph, struct ethhdr *p_st_mac, struct timeval *p_st_now)
{
    struct timeval st_timeval_pkg;

    #ifdef FRDBG_CAP_IN
        char arr_data_info[56];
        arr_data_info[0] = '\0';
        frl4_print2(arr_data_info, sizeof(arr_data_info), IPPROTO_UDP, addr->saddr, addr->source, addr->daddr, addr->dest);
        FRLOG_DEBUG("udp etype=0x%02x nids_linkoffset=%d src=[" FRMAC_FMT "] dst=[" FRMAC_FMT "] timestamp=%ld.%06ld %s data_len=%d"
                   , p_st_mac->h_proto, nids_linkoffset, FRMAC_ARG(p_st_mac->h_source), FRMAC_ARG(p_st_mac->h_dest)
                   , p_st_now->tv_sec, p_st_now->tv_usec
                   , arr_data_info, len);
    #endif

    if(g_flag_dump_file)
        gettimeofday (&g_st_timestamp_pkg_upd, NULL);

    if(g_flag_dump_file && g_i_use_system_time)
        gettimeofday (&st_timeval_pkg, NULL);
    else
        st_timeval_pkg = *p_st_now;

    frstat_pkg_add_frame_udp(1);
    frct_add((char *)p_st_mac->h_source, (char *)p_st_mac->h_dest, IPPROTO_UDP
            , addr->saddr, addr->source
            , addr->daddr, addr->dest
            , FR_YES, FRANALYZ_CMD_DATA
            , FR_NO, APM_CONNECT_ESTABLISHED, buf, len, st_timeval_pkg
            , g_flag_drop_timestamp_incorrect, 0);
    //FRPRINT_BIN("udp data:", buf, len);
    //frct_hash_output();
    return;

}
#endif

/*******************************************************************************
*  FUNC     :  tcp关闭时调用
*  ARGS     :  p_st_tcp                 (struct tcp_stream *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_tcp_free(struct tcp_stream *p_st_tcp)
{
    struct half_stream *p_st_half=NULL;
    struct timeval st_timeval_pkg;
    Franalyz_cmd em_analyz_cmd;
    
    if(g_i_flag_run == 0 || p_st_tcp == NULL)
        return;
    
    if(g_flag_dump_file)
        gettimeofday (&g_st_timestamp_pkg_upd, NULL);

    if (p_st_tcp->client.count_new)
        p_st_half = &p_st_tcp->client;
    else
        p_st_half = &p_st_tcp->server;

    st_timeval_pkg = p_st_half->now;
    
    if(g_flag_dump_file && g_i_use_system_time)
        gettimeofday (&st_timeval_pkg, NULL);

    if (p_st_tcp->nids_state == NIDS_RESET)
    {
        Conntrack *p_st_ct = frct_get(IPPROTO_TCP, p_st_tcp->addr.saddr, p_st_tcp->addr.source
                         , p_st_tcp->addr.daddr, p_st_tcp->addr.dest );
        if(p_st_ct)
            frstat_conns_add_reset(p_st_ct->src_ip, p_st_ct->dst_ip, p_st_ct->dst_port, 1);
        frct_put(p_st_ct);
        em_analyz_cmd = FRANALYZ_CMD_RESET;
    }
    else
    {
        em_analyz_cmd = FRANALYZ_CMD_FIN;
    }
    frstat_pkg_add_frame_fin(1);

    frct_del(IPPROTO_TCP
            , p_st_tcp->addr.saddr, p_st_tcp->addr.source
            , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
            , em_analyz_cmd, st_timeval_pkg);

    return;
}

/*******************************************************************************
*  FUNC     :  tcp层进行协议分析
*  ARGS     :  p_st_tcp                 (struct tcp_stream *)
*           :  this_time_not_needed     (void **)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_tcp_callback(struct tcp_stream *p_st_tcp, void ** this_time_not_needed)
{
    struct half_stream *p_st_half=NULL;
    int i_is_pcaptime=0, i_has_mac=0;
    const char *p_src_mac=NULL, *p_dst_mac=NULL;
    struct timeval st_timeval_pkg;

    if(g_i_flag_run == 0 || p_st_tcp == NULL)
        return;

    if(p_st_tcp->nids_state != NIDS_JUST_EST && p_st_tcp->nids_state != NIDS_DATA
            && p_st_tcp->nids_state != NIDS_CLOSE && p_st_tcp->nids_state != NIDS_RESET && p_st_tcp->nids_state != NIDS_TIMED_OUT
            && p_st_tcp->nids_state != NIDS_EXITING)
        return;

    if(g_flag_dump_file)
        gettimeofday (&g_st_timestamp_pkg_upd, NULL);

    //获取数据包时间
    if (p_st_tcp->client.count_new)
        p_st_half = &p_st_tcp->client;
    else
        p_st_half = &p_st_tcp->server;
    if(p_st_half)
    {
        i_is_pcaptime = 1;
        i_has_mac=1;
        st_timeval_pkg = p_st_half->now;
        p_src_mac = (const char *)p_st_half->st_mac.h_source;
        p_dst_mac = (const char *)p_st_half->st_mac.h_dest;
    }
    else
    {
        gettimeofday (&st_timeval_pkg, NULL);
        p_src_mac = "\0\0\0\0\0\0";
        p_dst_mac = "\0\0\0\0\0\0";
    }

    #ifdef FRDBG_CAP_IN
    if(i_has_mac)
    {
        FRLOG_DEBUG("tcp 1 etype=0x%02x nids_linkoffset=%d src=[" FRMAC_FMT "] dst=[" FRMAC_FMT "] timestamp=%ld.%06ld(%s) datalen=%d"
                   , p_st_half->st_mac.h_proto, nids_linkoffset, FRMAC_ARG(p_src_mac), FRMAC_ARG(p_dst_mac)
                   , st_timeval_pkg.tv_sec, st_timeval_pkg.tv_usec
                   , i_is_pcaptime ? "pcap time":"system time"
                   , p_st_half->count_new);
    }
    else
        FRLOG_DEBUG("tcp 2 nids_linkoffset=%d %ld.%06ld(%s) nids_state=%d(1:just_est;2:data;3:close;4:reset;5:timeout;6:exit)"
                   , nids_linkoffset
                   , st_timeval_pkg.tv_sec, st_timeval_pkg.tv_usec
                   , i_is_pcaptime ? "pcap time":"system time"
                   , p_st_tcp->nids_state);
    #endif

    if(g_flag_dump_file && g_i_use_system_time)
        gettimeofday (&st_timeval_pkg, NULL);

    //连接正式建立成功
    if(p_st_tcp->nids_state == NIDS_JUST_EST)
    {
        p_st_tcp->client.collect=1;
        p_st_tcp->server.collect=1;
        p_st_tcp->server.collect_urg=1;
        #ifdef WE_WANT_URGENT_DATA_RECEIVED_BY_A_CLIENT
                p_st_tcp->client.collect_urg=1;
        #endif

        //增加连接
        if(p_st_tcp->client.count_new)
            frct_add(p_src_mac,p_dst_mac, IPPROTO_TCP
                   , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                   , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                   , FR_NO, FRANALYZ_CMD_UNKNOWN
                   , FR_NO, APM_CONNECT_ESTABLISHED, NULL, 0, st_timeval_pkg
                   , g_flag_drop_timestamp_incorrect, 0);
        else
            frct_add(p_src_mac,p_dst_mac, IPPROTO_TCP
                   , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                   , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                   , FR_NO, FRANALYZ_CMD_UNKNOWN
                   , FR_NO, APM_CONNECT_ESTABLISHED, NULL, 0, st_timeval_pkg
                   , g_flag_drop_timestamp_incorrect, 0);
        //frct_hash_output();
        return;
    }

    //有处理数据
    if(p_st_tcp->nids_state == NIDS_DATA)
    {
        frstat_pkg_add_frame_tcp(1);
        if (p_st_tcp->client.count_new)
            p_st_half = &p_st_tcp->client;
        else
            p_st_half = &p_st_tcp->server;
        
        if(p_st_tcp->client.count_new)
            frct_add(p_src_mac,p_dst_mac, IPPROTO_TCP
                    , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                    , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                    , FR_YES, FRANALYZ_CMD_DATA
                    , FR_NO, APM_CONNECT_ESTABLISHED, p_st_half->data, p_st_half->count_new, st_timeval_pkg
                    , g_flag_drop_timestamp_incorrect, 0);
        else
            frct_add(p_src_mac,p_dst_mac, IPPROTO_TCP
                    , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                    , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                    , FR_YES, FRANALYZ_CMD_DATA
                    , FR_NO, APM_CONNECT_ESTABLISHED, p_st_half->data, p_st_half->count_new, st_timeval_pkg
                    , g_flag_drop_timestamp_incorrect, 0);
        //FRPRINT_BIN("tcp data:", p_st_half->data, p_st_half->count_new);
        //frct_hash_output();
        return;
    }

    return ;
}

/*******************************************************************************
*  FUNC     :  增加tcp的新建连接
*  ARGS     :  p_st_iphdr    (struct ip *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_add_tcp_new(struct ip *p_st_iphdr, struct tcp_stream *p_st_tcp, int i_status)
{
    struct half_stream *p_st_half=NULL;
    struct tcphdr *p_st_tcphdr = NULL;
    char *p_src_mac=NULL, *p_dst_mac=NULL;
    u_short src_port, dst_port;
    struct timeval st_timeval_pkg;

    if(g_i_flag_run == 0)
        return;

    if(p_st_iphdr == NULL || p_st_tcp == NULL || p_st_iphdr->ip_p != IPPROTO_TCP)
        return;

    if(g_flag_dump_file)
        gettimeofday (&g_st_timestamp_pkg_upd, NULL);

    p_st_half = &p_st_tcp->client;
    p_src_mac = (char *)p_st_half->st_mac.h_source;
    p_dst_mac = (char *)p_st_half->st_mac.h_dest;

    #ifdef FRDBG_CAP_IN
        FRLOG_DEBUG("tcp new etype=0x%02x nids_linkoffset=%d src=[" FRMAC_FMT "] dst=[" FRMAC_FMT "] timestamp=%ld.%06ld datalen=%d status=%d"
                   , p_st_half->st_mac.h_proto, nids_linkoffset, FRMAC_ARG(p_src_mac), FRMAC_ARG(p_dst_mac)
                   , p_st_half->now.tv_sec, p_st_half->now.tv_usec, p_st_half->count_new
                   , i_status);
    #endif

    p_st_tcphdr = (struct tcphdr *)( (u_char *)p_st_iphdr + 4 * p_st_iphdr->ip_hl);

    //#ifdef __FAVOR_BSD
        src_port = p_st_tcphdr->source;
        dst_port = p_st_tcphdr->dest;
    //#else
    //    src_port = p_st_tcphdr->th_sport;
    //    dst_port = p_st_tcphdr->th_dport;
    //#endif

    if(g_flag_dump_file && g_i_use_system_time)
        gettimeofday (&st_timeval_pkg, NULL);
    else
        st_timeval_pkg = p_st_half->now;
    //if ((p_st_tcphdr->th_flags & TH_SYN) &&
    //!(p_st_tcphdr->th_flags & TH_ACK) &&
    //!(p_st_tcphdr->th_flags & TH_RST))
    {
        if(i_status == APM_CONNECT_SYN_SENT)
        {
            frstat_pkg_add_frame_syn(1);
            //增加连接
            frct_add(p_src_mac, p_dst_mac, p_st_iphdr->ip_p
                    , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                    , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                    , FR_YES, FRANALYZ_CMD_SYN
                    , FR_NO, APM_CONNECT_SYN_SENT, NULL, 0, st_timeval_pkg
                    , g_flag_drop_timestamp_incorrect, 0);
        }
        else
        {
            /* tcp没有3次握手数据时，发生该情况
             * 增加连接,并设定ct状态为ESTABLISHED
             */
            frct_add(p_src_mac, p_dst_mac, p_st_iphdr->ip_p
                    , p_st_tcp->addr.saddr, p_st_tcp->addr.source
                    , p_st_tcp->addr.daddr, p_st_tcp->addr.dest
                    , FR_YES, FRANALYZ_CMD_SYN                                  //插入syn包，告诉协议分析器
                    , FR_NO, APM_CONNECT_ESTABLISHED, NULL, 0, st_timeval_pkg
                    , g_flag_drop_timestamp_incorrect, 0); //ct状态设定为ESTABLISHED
        }
        //frct_hash_output();
    }

    return;
}

/*******************************************************************************
*  FUNC     :  信号处理
*  ARGS     :  dunno    (信号量)
*  RTN      :  
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_sig(int dunno)
{
    switch (dunno) {
        case SIGHUP:
            //g_i_flag_run = 0;
            //event_base_loopbreak(g_p_st_ebase);
            printf("SIGHUP\n");
            break;
        case SIGINT:
            if(g_i_flag_run)
            {
                g_i_flag_run = 0;
                FRLOG_INFO("signal exit");
            }

            event_base_loopbreak(g_p_st_ebase);
            printf("SIGINT\n");
            break;
        case SIGQUIT:
            if(g_i_flag_run)
            {
                g_i_flag_run = 0;
                FRLOG_INFO("signal exit");
            }
            event_base_loopbreak(g_p_st_ebase);
            printf("SIGQUIT\n");
            break;
        case SIGPIPE:
            printf("SIGPIPE\n");
            break;
        default:
            break;
    }
    return;
}

/*******************************************************************************
*  FUNC     :  应用程序退出
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frame_cmd_exist(void )
{

    g_i_flag_run = 0;
    event_base_loopbreak(g_p_st_ebase);

    return;
}

/*******************************************************************************
*  FUNC     :  启动cui 命令行服务
*  ARGS     :  arg    (void *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_cmd_line(void *arg)
{

    FRLOG_INFO("cmd_line start");
    prctl(PR_SET_NAME,"cmd_line");
    frcmd_server_start();
    FRLOG_INFO("cmd_line end");

    pthread_exit(0);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  dump file mode时，检查程序终止
*  ARGS     :  arg    (void *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_chk_dump_close(void *arg)
{

    int i_loop=0;
    struct timeval st_timeval_now;

    FRLOG_INFO("__frame_chk_dump_close start");
    prctl(PR_SET_NAME,"chk_exit");
    //等待3sec
    for(i_loop=0; i_loop < g_i_pcap_wait; i_loop++)
    {
        printf("dump file mode, wait for do pcap(pcap_queue=%lu ct_count=%lu) %dsec...\n"
                , g_ul_pcap_queue_used, g_ul_ct_used, i_loop+1);
        sleep(1);
    }

    do
    {
        printf("dump file mode, wait for do pcap(pcap_queue=%lu ct_count=%lu)...\n"
                , g_ul_pcap_queue_used, g_ul_ct_used);
        gettimeofday (&st_timeval_now, NULL);

        //没有数据包 and 没有ct
        //或者 长时间(g_i_exit_wait)没有从文件中读取数据包, 程序退出
        if( (g_ul_pcap_queue_used < 1 && g_ul_ct_used < 1)
            || ( g_i_exit_wait > 0 && st_timeval_now.tv_sec - g_st_timestamp_pkg_upd.tv_sec >= g_i_exit_wait))
        {
            printf("dump file mode, programe exit(wait %d sec)\n", g_i_exit_wait);
            if(g_i_exit_wait > 0)
            {
                for(i_loop=0; i_loop < g_i_exit_wait; i_loop++)
                {
                    sleep(1);
                    printf("%dsec ", i_loop+1);
                    fflush(stdout);
                }
                printf("\n");
            }

            g_i_flag_run = 0;
            sleep(1);
            break;
        }
        sleep(1);
    }while(g_i_flag_run);

    FRLOG_INFO("__frame_chk_dump_close end");

    pthread_exit(0);

    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  触发timer事件
*  ARGS     :  arg    (void *)
*  RTN      :  
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_do_timer(void *arg)
{
    //struct timeval st_delay = {2, 0};
    
    g_i_task_chk_timer = FR_YES;
    pthread_detach(pthread_self());

    FRLOG_INFO("event_base_dispatch start");
    prctl(PR_SET_NAME,"timer");
    while(g_i_flag_run)
    {
        //if(nids_params.filename)
        //    event_base_loopexit(g_p_st_ebase, &st_delay);
        event_base_dispatch(g_p_st_ebase);
        usleep(100000);
    }
    g_i_task_chk_timer = FR_NO;
    FRLOG_INFO("event_base_dispatch end");
    pthread_exit(0);

    return (void*)NULL;
}

FR_STATIC void
udp_sleep(int i_time)
{
    int i = 0;

    for (i=0;i<i_time && g_i_flag_run;i++)
    {
        sleep(1);
    }
}


/*******************************************************************************
*  FUNC     :  在nids里面清空udp的过期连接信息
*  ARGS     :  arg    (void *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *
__remove_timeout_task(void *arg)
{
    while (g_i_flag_run)
    {
        nids_udp_rm_timeout_task();
        udp_sleep(nids_params.i_udp_cache_time);
    }
    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  从上报信息中统计连接数信息
*  ARGS     :  arg    (void *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void *__frame_stat_conn(void *arg)
{
    struct timeval st_time_start,st_time_end, st_delay;
    time_t st_now;
    struct tm *p_tmp_now=NULL;
    long l_time_diff=0, l_repeat_time = 0, l_sec;
    int i_first=0;

    l_repeat_time = st_apm_params.ui_stat_conn_time * 1000000;
    FRLOG_INFO("__frame_stat_conn start");
    prctl(PR_SET_NAME,"stat_conns");

    //从0秒开始统计
    time(&st_now);
    p_tmp_now = localtime(&st_now);
    if(p_tmp_now->tm_sec >= 0 && p_tmp_now->tm_sec < 60)
    {
        gettimeofday(&st_time_start, NULL);
        l_sec = 60 -  p_tmp_now->tm_sec;
        st_delay.tv_usec = 1000000 - st_time_start.tv_usec;
        if(l_sec >0 && st_delay.tv_usec >0 )
            l_sec -= 1;

        i_first = 1;
        do
        {
            if(l_sec > 0)
                st_delay.tv_sec = 1;
            else
                st_delay.tv_sec = 0;
            l_sec -= 1;
            if(i_first)
            {
                i_first = 0;
                st_delay.tv_usec = (l_repeat_time -l_time_diff) % 1000000;
            }
            else
                st_delay.tv_usec = 0;
            select(0, NULL, NULL, NULL, &st_delay);
        } while (g_i_flag_run && l_sec > 0);
    }

    //60sec上报
    while(g_i_flag_run)
    {
        gettimeofday(&st_time_start, NULL);
        //连接信息上层不处理, 暂时不上报
        //frstat_conns_report();
        frstat_ports_report();

        gettimeofday(&st_time_end, NULL);
        l_time_diff = (st_time_end.tv_sec - st_time_start.tv_sec) * 1000000
                    + (st_time_end.tv_usec - st_time_start.tv_usec);

        //延迟
        if(l_repeat_time - l_time_diff > 0)
        {
            l_sec = (l_repeat_time -l_time_diff) / 1000000;
            i_first = 1;

            //延迟到0秒
            do
            {
                if(l_sec > 0)
                    st_delay.tv_sec = 1;
                else
                    st_delay.tv_sec = 0;
                l_sec -= 1;
                if(i_first)
                {
                    i_first = 0;
                    st_delay.tv_usec = (l_repeat_time -l_time_diff) % 1000000;
                }
                else
                    st_delay.tv_usec = 0;
                select(0, NULL, NULL, NULL, &st_delay);
            } while(g_i_flag_run && l_sec > 0);
        }
    }

    FRLOG_INFO("__frame_stat_conn end");
    return (void*)NULL;
}
/*******************************************************************************
*  FUNC     :  Frframe_ref初始化
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
void __frame_set_context(void)
{
    frexpect_setRef(g_st_apm_context.p_st_exp_ref);
    frexpect2_setRef(g_st_apm_context.p_st_exp2_ref);
    frservice_setRef(g_st_apm_context.p_st_service_ref);
    frreport_session_mng_setRef(g_st_apm_context.p_st_report_session_ref);
    frreport_mng_setRef((Report_module *) (g_st_apm_context.p_st_report_moduleRef) );
    g_st_apm_context.p_st_log_category = frlog_get_hd();

    return;
}

/*******************************************************************************
*  FUNC     :  frame初始化
*  ARGS     :
*  RTN      :  FR_SUCC:成功, FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frame_init(int i_flag_run_dumpfile, const char *p_debugstr)
{
    int i_ret_fun=0, i_loop=0;
    
    //初始化libevent
    if(evthread_use_pthreads())
    {
        FRLOG_ERROR_DETAIL("evthread_use_pthreads err");
        return FR_FAIL;
    }

    #ifdef FRDBG_CT_DBG
    event_enable_debug_mode();
    #endif

    if(g_p_st_ebase == NULL)
        g_p_st_ebase = event_base_new();

    if(g_p_st_ebase == NULL)
    {
        FRLOG_ERROR_DETAIL("event_base_new err");
        return FR_FAIL;
    }
    //初始化时钟管理
    i_ret_fun = frtimer_init();
    if(i_ret_fun != FR_SUCC)
    {
        event_base_free(g_p_st_ebase);
        FRLOG_ERROR_DETAIL("frtimer_init err");
        return FR_FAIL;
    }
    //初始化上报数据模块
    i_ret_fun = frreport_mng_init();
    if(i_ret_fun != FR_SUCC)
    {
        frtimer_destory();
        event_base_free(g_p_st_ebase);
        FRLOG_ERROR_DETAIL("frreport_conn_init err");
        return FR_FAIL;
    }
    //初始化连接统计模块
    i_ret_fun = frstat_conns_init(st_apm_params.ui_ct_hash_size);
    if(i_ret_fun != FR_SUCC)
    {
        frreport_mng_destory();
        frtimer_destory();
        event_base_free(g_p_st_ebase);
        FRLOG_ERROR_DETAIL("frreport_conn_init err");
        return FR_FAIL;
    }
    //初始化端口统计模块
    i_ret_fun = frstat_ports_init(10000);
    if(i_ret_fun != FR_SUCC)
    {
        frstat_conns_destroy();
        frreport_mng_destory();
        frtimer_destory();
        event_base_free(g_p_st_ebase);
        FRLOG_ERROR_DETAIL("frreport_conn_init err");
        return FR_FAIL;
    }

    //创建任务处理线程
    g_p_thread_id_do_task = (pthread_t *) frmalloc(sizeof(pthread_t) * g_i_do_task_cnt);
    if(g_p_thread_id_do_task == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        goto ERROR_EBASE;
    }
    memset(g_p_thread_id_do_task, '\0', sizeof(pthread_t) * g_i_do_task_cnt);
    for(i_loop=0; i_loop<g_i_do_task_cnt; i_loop++)
    {
        i_ret_fun = pthread_create(g_p_thread_id_do_task+i_loop, NULL, frtask_do, NULL);
        if(i_ret_fun)
        {
            *(g_p_thread_id_do_task+i_loop) = 0;
            FRLOG_ERROR_DETAIL("pthread_create frtask_do num=[%d] err", i_loop);
            continue;
        }
        g_ui_threads++;
    }

    //时钟检查线程
    i_ret_fun = pthread_create(&g_thread_id_do_timer, NULL, __frame_do_timer, NULL);
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("pthread_create __frame_do_timer err");
        goto ERROR_THREAD;
    }
    g_ui_threads += 1;

    //数据上报线程
    i_ret_fun = pthread_create(&g_thread_id_report, NULL, frreport_mng_task, NULL);
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("pthread_create frreport_mng_task err");
        goto ERROR_THREAD;
    }
    g_ui_threads += 1;
    if(p_debugstr != NULL && *p_debugstr != '\0')
        frreport_debug(p_debugstr);

    /* 上报信息中统计连接数 */
    i_ret_fun = pthread_create(&g_thread_id_stat_conn, NULL, __frame_stat_conn, NULL);
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("pthread_create __frame_stat_conn err");
        goto ERROR_THREAD;
    }
    g_ui_threads += 1;
    
    /* 接收ssl解析后的数据 */
    i_ret_fun = pthread_create(&g_thread_ct_ssl_mng, NULL, frct_ssl_mng, NULL);
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("pthread_create frct_ssl_mng err");
        goto ERROR_THREAD;
    }
    g_ui_threads += 1;

    //dump file mode时，检查程序终止
    if(i_flag_run_dumpfile == FR_YES)
    {
        i_ret_fun = pthread_create(&g_thread_id_chk_dump, NULL, __frame_chk_dump_close, NULL);
        if(i_ret_fun)
        {
            FRLOG_ERROR_DETAIL("pthread_create __frame_chk_dump_close err");
            goto ERROR_THREAD;
        }
        g_ui_threads += 1;
    }

    //命令行对应
    //if(nids_params.filename == NULL)
    {
        i_ret_fun = pthread_create(&g_thread_id_cmd_line, NULL, __frame_cmd_line, NULL);
        if(i_ret_fun)
        {
            FRLOG_ERROR_DETAIL("pthread_create __frame_cmd_line err");
            goto ERROR_THREAD;
        }
        g_ui_threads += 1;
    }

    //定时清空udp的连接
    {
        i_ret_fun = pthread_create(&g_thread_udp_drop, NULL, __remove_timeout_task, NULL);
        if(i_ret_fun)
        {
            FRLOG_ERROR_DETAIL("pthread_create __remove_timeout_task err");
            goto ERROR_THREAD;
        }
        g_ui_threads += 1;
    }

    //过滤规矩加载
    i_ret_fun = apm_filter_init();
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("apm_filter_init err");
        goto ERROR_THREAD;
    }
    //加载lua脚本
    i_ret_fun = frlua_config_init();
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("frlua_config_init err");
        apm_filter_destroy();
        goto ERROR_THREAD;
    }
    i_ret_fun = frlua_config_load();
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("frlua_config_load err");
        //frlua_config_destroy();
        //apm_filter_destroy();
        //goto ERROR_THREAD;
    }

    i_ret_fun = frssl_config_init();
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("frssl_config_init err");
        frlua_config_destroy();
        apm_filter_destroy();
        goto ERROR_THREAD;
    }
    i_ret_fun = frssl_config_load();
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("frssl_config_load err");
        //frlua_config_destroy();
        //apm_filter_destroy();
        //goto ERROR_THREAD;
    }
    
    frexpect_init(st_apm_params.ui_relative_timeout);
    frexpect2_init(st_apm_params.ui_relative_timeout);
    frservice_mng_init();
    frreport_session_mng_init(0);
    //具体协议模块这时还没有解码,更改框架引用参数没有问题
    __frame_set_context();

    //模块信息初始化
    frmodule_mng_init();
    i_ret_fun = frproto_mng_init();
    if(i_ret_fun == FR_FAIL)
    {
        frreport_session_mng_destory();
        frservice_mng_destory();
        frexpect2_destory();
        frexpect_destory();
        frssl_config_destroy();
        frlua_config_destroy();
        apm_filter_destroy();
        FRLOG_ERROR_DETAIL("frproto_mng_init err");
        goto ERROR_THREAD;
    }
    //为了调试其他模块,模块加载出错,程序也继续
    frmodule_cfg_load();
    frproto_cfg_load(FR_NO);
    frproto_l7default_load(FR_NO);

    //加载模块统计
    __frame_stat_init();
    i_loop=0;
    i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_module, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_stat_module err");
    else
    {
        i_loop++;
        g_ui_threads++;
    }
    i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_system, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_stat_system err");
    else
    {
        i_loop++;
        g_ui_threads++;
    }
    i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_l4_tcp, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_stat_l4_tcp err");
    else
    {
        i_loop++;
        g_ui_threads++;
    }
    i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_thread, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_stat_thread err");
    else
    {
        i_loop++;
        g_ui_threads++;
    };
    i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_server, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_stat_server err");
    else
    {
        i_loop++;
        g_ui_threads++;
    };
    if(i_flag_run_dumpfile == FR_NO)
    {
        i_ret_fun = pthread_create(&g_thread_id_stat[i_loop], NULL, __frame_stat_packet_rcv, NULL);
        if(i_ret_fun)
            FRLOG_ERROR_DETAIL("pthread_create __frame_stat_packet_rcv err");
        else
        {
            i_loop++;
            g_ui_threads++;
        };
    }

    //任务管理加载
    i_ret_fun = frtask_mng_init();
    if(i_ret_fun == FR_FAIL)
    {
        __frame_stat_destory();
        frproto_mng_destory();
        frreport_session_mng_destory();
        frservice_mng_destory();
        frexpect2_destory();
        frexpect_destory();
        frssl_config_destroy();
        frlua_config_destroy();
        apm_filter_destroy();
        goto ERROR_THREAD;
    }

    i_ret_fun = frct_init(st_apm_params.ui_ct_hash_size);
    if(i_ret_fun == FR_FAIL)
    {
        __frame_stat_destory();
        frtask_mng_destory();
        frproto_mng_destory();
        frreport_session_mng_destory();
        frservice_mng_destory();
        frexpect2_destory();
        frexpect_destory();
        frssl_config_destroy();
        frlua_config_destroy();
        apm_filter_destroy();
        goto ERROR_THREAD;
    }

    i_ret_fun = pthread_create(&g_thread_id_chk_exp, NULL, __frame_clean_expect, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_clean_expect err");
    else
        g_ui_threads++;
    i_ret_fun = pthread_create(&g_thread_id_chk_lua, NULL, __frame_clean_lua_cfg, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_clean_lua err");
    else
        g_ui_threads++;
    i_ret_fun = pthread_create(&g_thread_id_chk_report_session, NULL, __frame_clean_report_session, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_clean_report_session err");
    else
        g_ui_threads++;

    i_ret_fun = pthread_create(&g_thread_id_http_srv, NULL, __frame_http_srv, NULL);
    if(i_ret_fun)
        FRLOG_ERROR_DETAIL("pthread_create __frame_http_srv err");
    else
        g_ui_threads++;

    return FR_SUCC;

ERROR_THREAD:
    g_i_flag_run=0;
    frdbg("pthread_join start\n");
    if(g_thread_id_http_srv)
    {
        pthread_cancel(g_thread_id_http_srv);
        pthread_join(g_thread_id_http_srv, NULL);
    }
    if(g_thread_id_chk_report_session)
        pthread_join(g_thread_id_chk_report_session, NULL);
    if(g_thread_id_chk_lua)
        pthread_join(g_thread_id_chk_lua, NULL);
    if(g_thread_id_chk_exp)
        pthread_join(g_thread_id_chk_exp, NULL);
    if(g_thread_id_stat_conn)
        pthread_join(g_thread_id_stat_conn, NULL);
    if(g_thread_ct_ssl_mng)
        pthread_join(g_thread_ct_ssl_mng, NULL);
    if(g_thread_id_report)
        pthread_join(g_thread_id_report, NULL);
    if(g_thread_id_chk_dump)
        pthread_join(g_thread_id_chk_dump, NULL);
    if(g_thread_id_cmd_line)
        pthread_join(g_thread_id_cmd_line, NULL);
    if(g_thread_udp_drop)
        pthread_join(g_thread_udp_drop, NULL);
    for(i_loop=0; i_loop<APM_STAT_CNT; i_loop++)
    {
        if(g_thread_id_stat[i_loop])
            pthread_join(g_thread_id_stat[i_loop], NULL);
    }
    if (nids_params.filename)
    {
        pthread_join(g_thread_id_pcap[0], NULL);
    }
    else
    {
        for (i_loop=0;i_loop<g_i_pcap_threads;i_loop++)
            pthread_join(g_thread_id_pcap[i_loop], NULL);
    }
    for(i_loop=0;i_loop<g_i_nids_threads;i_loop++)
        pthread_join(g_thread_nids[i_loop], NULL);
    //释放网口设备列表
    frlist_remove_all(&g_st_lst_head_dev, __frame_devs_node_free);

    for(i_loop=0; g_p_thread_id_do_task && i_loop<g_i_do_task_cnt; i_loop++)
    {
        if(g_p_thread_id_do_task[i_loop])
            pthread_join(g_p_thread_id_do_task[i_loop], NULL);
    }
    if(g_p_thread_id_do_task)
    {
        frfree(g_p_thread_id_do_task);
        g_p_thread_id_do_task = NULL;
    }

    //时钟检查线程退出
    //if(g_thread_id_do_timer)
    //    pthread_join(g_thread_id_do_timer, NULL);
    i_loop = 0;
    while(g_i_task_chk_timer == FR_YES && i_loop++ < 10)
    {
        event_base_loopbreak(g_p_st_ebase);
        sleep(1);
    }
    if(g_i_task_chk_timer == FR_YES && i_loop >= 10)
        FRLOG_WARN("event_base_dispatch fail");

    frdbg("pthread_join end\n");

ERROR_EBASE:
    if(g_p_st_ebase)
    {
        frstat_ports_destroy();
        frstat_conns_destroy();
        frreport_mng_destory();
        frtimer_destory();
        event_base_free(g_p_st_ebase);
    }

    return FR_FAIL;
}


/*******************************************************************************
*  FUNC     :  frame资源释放
*  ARGS     :  
*  RTN      :  
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frame_destory(void)
{
    int i_loop;

    FRLOG_INFO("pthread_join start");
    if(g_thread_id_http_srv)
    {
        pthread_cancel(g_thread_id_http_srv);
        pthread_join(g_thread_id_http_srv, NULL);
    }
    if(g_thread_id_chk_report_session)
        pthread_join(g_thread_id_chk_report_session, NULL);
    if(g_thread_id_chk_lua)
        pthread_join(g_thread_id_chk_lua, NULL);
    if(g_thread_id_chk_exp)
        pthread_join(g_thread_id_chk_exp, NULL);
    if(g_thread_id_stat_conn)
        pthread_join(g_thread_id_stat_conn, NULL);
    if(g_thread_ct_ssl_mng)
        pthread_join(g_thread_ct_ssl_mng, NULL);
    if(g_thread_id_report)
        pthread_join(g_thread_id_report, NULL);
    if(g_thread_id_chk_dump)
        pthread_join(g_thread_id_chk_dump, NULL);
    if(g_thread_id_cmd_line)
        pthread_join(g_thread_id_cmd_line, NULL);
    if(g_thread_udp_drop)
        pthread_join(g_thread_udp_drop, NULL);
    for(i_loop=0; i_loop<APM_STAT_CNT; i_loop++)
    {
        if(g_thread_id_stat[i_loop])
            pthread_join(g_thread_id_stat[i_loop], NULL);
    }
    if (nids_params.filename)
    {
        pthread_join(g_thread_id_pcap[0], NULL);
    }
    else
    {
        for (i_loop=0;i_loop<g_i_pcap_threads;i_loop++)
            pthread_join(g_thread_id_pcap[i_loop], NULL);
    }
    for(i_loop=0;i_loop<g_i_nids_threads;i_loop++)
        pthread_join(g_thread_nids[i_loop], NULL);
    //释放网口设备列表
    frlist_remove_all(&g_st_lst_head_dev, __frame_devs_node_free);
    
    g_i_flag_nids_init = FR_NO;
    apm_unregister_tcp_new();
    apm_unregister_tcp_free();
    nids_unregister_tcp(__frame_tcp_callback);
    #ifdef FRFRAME_DO_UDP
    nids_unregister_udp(__frame_udp_callback);
    #endif
    for (i_loop=0;i_loop<g_i_nids_threads;i_loop++)
    {
        nids_stream_exit(&g_st_nids_ip_tcp_stream[i_loop]);
    }
    nids_exit();

    //任务分配线程
    for(i_loop=0; g_p_thread_id_do_task && i_loop<g_i_do_task_cnt; i_loop++)
    {
        if(g_p_thread_id_do_task[i_loop])
            pthread_join(g_p_thread_id_do_task[i_loop], NULL);
    }
    if(g_p_thread_id_do_task)
    {
        frfree(g_p_thread_id_do_task);
        g_p_thread_id_do_task = NULL;
    }
    FRLOG_INFO("pthread_join end");

    //时钟检查线程退出
    //if(g_thread_id_do_timer)
    //    pthread_join(g_thread_id_do_timer, NULL);
    i_loop = 0;
    while(g_i_task_chk_timer == FR_YES && i_loop++ < 10)
    {
        event_base_loopbreak(g_p_st_ebase);
        sleep(1);
    }
    if(g_i_task_chk_timer == FR_YES && i_loop >= 10)
        FRLOG_WARN("event_base_dispatch fail");

    frtask_mng_destory();
    //调试用输出
    //frct_hash_output();
    frct_destroy();

    frreport_session_mng_destory();//必须在frmodule_mng_destory调用前
    frproto_mng_destory();
    frmodule_mng_destory();
    frservice_mng_destory();
    frexpect2_destory();
    frexpect_destory();
    frssl_config_destroy();
    frlua_config_destroy();
    apm_filter_destroy();
    __frame_stat_destory();

    if(g_p_st_ebase)
    {
        frstat_ports_destroy();
        frstat_conns_destroy();
        frreport_mng_destory();
        frtimer_destory();
        event_base_free(g_p_st_ebase);
    }

    return;
}


/*******************************************************************************
*  FUNC     :  初始化pcap句柄
*  ARGS     :  pcap(命令行)
*  RTN      :  0 (success)
*           :  其他 (failed)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __daq_init(int i_module_type)
{
    const char *arr_dirs[]={"/usr/local/lib/daq", NULL};
    const char *p_module_name=DAQ_MODULE_PCAP;
    int i_ret_fun=0;
    
    i_ret_fun = DAQ_Load(arr_dirs);
    if(i_ret_fun != DAQ_SUCCESS)
    {
        FRLOG_ERROR("DAQ_Load error");
        return DAQ_ERROR;
    }
    if(i_module_type == 1)
        p_module_name = DAQ_MODULE_AFPACKET;
    
    i_ret_fun = DAQ_Init(p_module_name);
    if(i_ret_fun != DAQ_SUCCESS)
    {
        FRLOG_ERROR("DAQ_Init error");
        DAQ_Unload();
        return DAQ_ERROR;
    }

    return DAQ_SUCCESS;
}

FR_STATIC int __frame_nids_init(void)
{
    int i = 0;
    
    memset(&g_st_nids_ip_tcp_stream, 0x00, sizeof(struct nids_ip_tcp_stream)*APM_DEV_MAX);
    
    for (i=0;i<g_i_nids_threads;i++)
    {
        if (!nids_stream_init(&g_st_nids_ip_tcp_stream[i]))
        {
            FRLOG_ERROR_DETAIL("nids_init err[%s]", nids_errbuf);
            frwarn("nids_init err[%s]\n", nids_errbuf);
            return FR_FAIL;
        }
    }
    g_i_flag_nids_init = FR_YES;
    
    apm_register_tcp_new(__frame_add_tcp_new);
    apm_register_tcp_free(__frame_tcp_free);
    
    nids_register_tcp(__frame_tcp_callback);
    #ifdef FRFRAME_DO_UDP
    nids_register_udp(__frame_udp_callback);
    #endif
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  根据pcap连接状态和数据包头信息，计算ip头需要跳过的长度
*  ARGS     :  p_data(数据包内容)
*           :  i_len(数据包长度)
*           :  p_i_offset(需要跳过的长度)
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed、数据包错误)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __pcap_chk_linktype(const unsigned char *p_data, int i_len, int i_link_type, int *p_i_offset)
{
    int i_linkoffset = 14;
    
    switch (i_link_type) {
        case DLT_EN10MB:
        {
            int i_offset = 12;
            
check_ip_type:
            if (i_len < i_offset + 2)
                return FR_FAIL;
            /* Only handle IP packets and 802.1Q VLAN tagged packets below. */
        	if (p_data[i_offset] == 8 && p_data[i_offset + 1] == 0) {
                /* Regular ethernet */
                break;
            } else if (p_data[i_offset] == 0x81 && p_data[i_offset + 1] == 0) {
                /* Skip 802.1Q VLAN and priority information */
                i_linkoffset += 4;
                i_offset += 4;
                goto check_ip_type;
            } else if (p_data[i_offset] == 0x88 && p_data[i_offset + 1] == 0x47) {
                /* Skip mpls */
                i_linkoffset += 4;
            } else if (p_data[i_offset] == 0x88 && p_data[i_offset + 1] == 0x48) {
                /* Skip mpls multi */
                i_linkoffset += 4;
            } else if (p_data[i_offset] == 0x88 && p_data[i_offset + 1] == 0x64) {
                /* Skip pppoe */
                i_linkoffset += 8;
            }
        	else
                /* non-ip frame */
                return FR_FAIL;
        }
        break;
    }
    *p_i_offset = i_linkoffset;
    return FR_SUCC;
}

FR_STATIC int __frame_pcap_get_index(const unsigned char *p_data, int i_len, int i_link_type, int *p_i_index)
{
    int i_linkoffset = 0;
    int i_index = 0;
    struct ip *iph = NULL;
    
    if (__pcap_chk_linktype(p_data, i_len, i_link_type, &i_linkoffset) != FR_SUCC)
        return FR_FAIL;
    
    iph = (struct ip *)(p_data + i_linkoffset);
    
    i_index = ((ntohl((unsigned int)iph->ip_src.s_addr)) % g_i_nids_threads
            + (ntohl((unsigned int)iph->ip_dst.s_addr)) % g_i_nids_threads) %g_i_nids_threads;
    
    *p_i_index = i_index;
    return FR_SUCC;
}

FR_STATIC void __frame_pcap_task_add(void * par
                        , DAQ_PktHdr_t *header, u_char * p_packet)
{
    struct nids_pcap_data *p_st_new = NULL;
    struct nids_pcap_data *p_st_tail = NULL;
    int i_index = 0;
    struct nids_ip_tcp_stream *p_st_nids_stream = NULL;
    int i_link_type = (int)((long)par);

    if (header == NULL || p_packet == NULL)
        return;
        
    //根据源ip目的ip获取对应的线程id
    if (__frame_pcap_get_index(p_packet, header->caplen, i_link_type, &i_index) != FR_SUCC)
        return;
        
    p_st_nids_stream = &g_st_nids_ip_tcp_stream[i_index];
        
    p_st_new = (struct nids_pcap_data *)malloc(sizeof(struct nids_pcap_data));
    if (p_st_new == NULL)
        return;
    memset(p_st_new, 0x00, sizeof(struct nids_pcap_data));
    p_st_new->p_hdr = (DAQ_PktHdr_t *)malloc(sizeof(DAQ_PktHdr_t));
    if (p_st_new->p_hdr == NULL)
    {
        free(p_st_new);
        return;
    }
    
    p_st_new->p_data = (u_char *)malloc(header->pktlen);
    if (p_st_new->p_data == NULL)
    {
        free(p_st_new->p_hdr);
        free(p_st_new);
        return;
    }
    
    memcpy(p_st_new->p_hdr, header, sizeof(DAQ_PktHdr_t));
    memcpy(p_st_new->p_data, p_packet, header->pktlen);
    p_st_new->i_link_type = i_link_type;
    
    pthread_spin_lock(&p_st_nids_stream->st_spin_nids_pcap_lock);
    p_st_tail = p_st_nids_stream->st_nids_pcap_header.tail;
    if (p_st_tail)
        p_st_tail->next = p_st_new;
    else
        p_st_nids_stream->st_nids_pcap_header.head = p_st_new;
    
    p_st_nids_stream->st_nids_pcap_header.tail = p_st_new;
    p_st_nids_stream->st_nids_pcap_header.size++;
    
    pthread_spin_unlock(&p_st_nids_stream->st_spin_nids_pcap_lock);
}

static void __frame_pcap_handler(void * par, DAQ_PktHdr_t *header, u_char * p_packet)
{
//	__nids_pcap_handler((struct nids_ip_tcp_stream *)par, g_i_pcap_linktype, NULL, header, p_packet);
//    return;
    __frame_pcap_task_add(par, header, p_packet);
    return;
}

static DAQ_Verdict frame_pcap_handler(void* user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt)
{
    __frame_pcap_handler(user, (DAQ_PktHdr_t *)pkthdr, (u_char *)pkt);
    return DAQ_VERDICT_PASS;
}

FR_STATIC void *__frame_nids(void *arg)
{
    struct nids_ip_tcp_stream *p_st_nids_ip_tcp_stream = NULL;
    
    prctl(PR_SET_NAME,"pcap_nids");
    if (arg == NULL)
        return (void*)NULL;
    
    p_st_nids_ip_tcp_stream = (struct nids_ip_tcp_stream *)arg;
    
    if(g_flag_dump_file)
    {
        sleep(2);
        nids_run (p_st_nids_ip_tcp_stream);
    }
    else
    {
        while(g_i_flag_run)
        {
            //nids_next();
            nids_dispatch(p_st_nids_ip_tcp_stream, 1);
        }
    }
    
    return (void*)NULL;
}

FR_STATIC void *__frame_daq(void *arg)
{
    int i_ret = 0;
    int i_pcap_time = 1024;
    char arr_err[PCAP_ERRBUF_SIZE];
    char *p_dev = NULL, *p_result = NULL;
    void *p_daq_hand = NULL;
    int i_daq_linktype = -1;
    
    prctl(PR_SET_NAME,"pcap_daq");
    if (arg)
        p_dev = (char *)arg;
    
    if (g_flag_dump_file)
    {
        p_daq_hand = DAQ_New(DAQ_MODE_READ_FILE, nids_params.filename, nids_params.ring_size
                      , nids_params.snaplen, i_pcap_time, arr_err, sizeof(arr_err), &i_daq_linktype);
        if(p_daq_hand == NULL)
            goto err;
    }
    else if (p_dev)
    {
        p_daq_hand = DAQ_New(DAQ_MODE_PASSIVE, p_dev, nids_params.ring_size
                      , nids_params.snaplen, i_pcap_time
                      , arr_err, sizeof(arr_err), &i_daq_linktype);
        if(p_daq_hand == NULL)
            goto err;
    }
    else
        goto err;
    
    i_ret = DAQ_Start(p_daq_hand, arr_err, sizeof(arr_err), &i_daq_linktype);
    if(i_ret != DAQ_SUCCESS)
        goto err;

    i_ret = apm_filter_load(p_daq_hand, &p_result);
    if(i_ret)
    {
        FRLOG_ERROR_DETAIL("apm_filter_load err, [%s]", p_result);
    }
    if (p_result)
        frfree(p_result);

    //保存daq句柄
    {
        Frlist_node *p_st_node = NULL;
        p_st_node = FRLIST_FIRST_NODE(&g_st_lst_head_dev);
        while(p_st_node)
        {
            Nids_handle *p_nids_handle = NULL;
            const char *p_dev_one = NULL;
            
            p_nids_handle = (Nids_handle *)FRLIST_GET_NODE_DATA(p_st_node);
            if (p_nids_handle == NULL || p_nids_handle->p_dev == NULL)
                break;
            
            p_dev_one = p_nids_handle->p_dev;
            if (strcmp(p_dev_one, p_dev) == 0)
            {
                p_nids_handle->p_daq_hand = p_daq_hand;
                break;
            }
            
            p_st_node = FRLIST_NEXT_NODE(p_st_node);
        }
    }
    
    while (g_i_flag_run)
    {
        if (g_flag_dump_file)
        {
            DAQ_Acquire(p_daq_hand, -1, frame_pcap_handler, (void *)i_daq_linktype);
            break;
        }
        DAQ_Acquire(p_daq_hand, 1, frame_pcap_handler, (void *)i_daq_linktype);
    }
    
    return (void*)NULL;
err:
    return (void*)NULL;
}

FR_STATIC void __frame_devs_node_free(Frlist_node* node)
{
    Nids_handle *p_nids_handle = NULL;
    
    if (node == NULL || node->data == NULL)
        return;
    p_nids_handle = (Nids_handle *)node->data;
    if (p_nids_handle->p_dev)
        frfree((char *)p_nids_handle->p_dev);
    if (p_nids_handle->p_daq_hand)
        DAQ_Stop(p_nids_handle->p_daq_hand);
    frfree(p_nids_handle);
}

FR_STATIC void __frame_get_devs(const char *p_dev, Frlist_header *p_list_head)
{
    char *p_tmp = NULL;
    char *p_dev_one = NULL;
    int i_dev_len = 0;
    Frlist_node *p_st_new = NULL;
    
    if (p_dev == NULL)
        return;
    do
    {
        Nids_handle *p_nids_handle = NULL;
        
        //dev用","分割
        p_tmp = strchr((char *)p_dev, ',');
        if (p_tmp == NULL)
        {
            i_dev_len = strlen(p_dev);
        }
        else
        {
            i_dev_len = p_tmp - p_dev;
        }
        p_dev_one = (char *)frmemdup(p_dev, i_dev_len + 1);
        if (p_dev_one == NULL)
            return;
        p_dev_one[i_dev_len] = '\0';
        
        p_nids_handle = (Nids_handle *)frmalloc(sizeof(Nids_handle));
        if (p_nids_handle == NULL)
        {
            frfree(p_dev_one);
            return;
        }
        p_nids_handle->p_dev = p_dev_one;
        p_nids_handle->p_daq_hand = NULL;
        p_st_new = frlist_node_create(p_nids_handle);
        if (p_st_new == NULL)
        {
            frfree(p_dev_one);
            frfree(p_nids_handle);
            return;
        }
        frlist_add_tail(p_list_head, p_st_new);
        if (p_tmp == NULL)
            return;
        p_dev = p_tmp + 1;
    }
    while (p_tmp);
}

/*******************************************************************************
*  FUNC     :  抓包分析
*  ARGS     :  p_pcap_filename      (测试用pcap文件)
*  RTN      :  FR_SUCC:成功, FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frame_do_analyser(const char *p_dev, int i_dumpfile_times
                                 , const char *p_debugstr)
{
    int i_ret=FR_SUCC, i_ret_fun = 0, i_loop=0, i_flag_run_dumpfile;

    if(nids_params.filename)
        i_flag_run_dumpfile = FR_YES;
    else
        i_flag_run_dumpfile = FR_NO;

    i_ret_fun = __frame_init(i_flag_run_dumpfile, p_debugstr);
    if(i_ret_fun == FR_FAIL)
    {
        FRLOG_ERROR_DETAIL("frame_init err");
        return FR_FAIL;
    }

    if(i_dumpfile_times <0)
        i_dumpfile_times = 1;

    FRLOG_INFO("apm analyse run...");
    printf("apm analyse run...\n");
    
    signal(SIGHUP, __frame_sig);
    signal(SIGINT, __frame_sig);
    signal(SIGQUIT, __frame_sig);
    signal(SIGPIPE, __frame_sig);
    signal(SIGUSR1, __frame_sig);

    i_loop=1;
    
    do
    {
        if (__daq_init(nids_params.i_module_type) != DAQ_SUCCESS)
            goto END;
            
        if (!nids_init())
            goto END;
            
        if (__frame_nids_init() != FR_SUCC)
            goto END;

        //解析网口，存储到设备列表
        frlist_header_init(&g_st_lst_head_dev);
        __frame_get_devs(p_dev, &g_st_lst_head_dev);
        if (frlist_size(&g_st_lst_head_dev) == 0)
        {
            FRLOG_ERROR_DETAIL("dev error,dev=[%s]", p_dev);
            goto END;
        }

        //调试数据包
        if(i_flag_run_dumpfile==FR_YES)
        {
            Frlist_node *p_st_node = NULL;
            
            p_st_node = FRLIST_FIRST_NODE(&g_st_lst_head_dev);
            if (p_st_node)
            {
                Nids_handle *p_nids_handle = NULL;
                const char *p_dev_one = NULL;
                p_nids_handle = (Nids_handle *)FRLIST_GET_NODE_DATA(p_st_node);
                if (p_nids_handle)
                {
                    p_dev_one = p_nids_handle->p_dev;
                    i_ret_fun = pthread_create(&g_thread_id_pcap[0], NULL, __frame_daq, (void *)p_dev_one);
                    if(i_ret_fun)
                    {
                        FRLOG_ERROR_DETAIL("pthread_create __frame_daq err");
                        i_ret = FR_FAIL;
                        goto END;
                    }
                    g_i_pcap_threads = 1;
                }
            }
        }
        else
        {
            Frlist_node *p_st_node = NULL;
            int i_loop = 0;
            
            p_st_node = FRLIST_FIRST_NODE(&g_st_lst_head_dev);
            while(p_st_node)
            {
                Nids_handle *p_nids_handle = NULL;
                const char *p_dev_one = NULL;
                
                p_nids_handle = (Nids_handle *)FRLIST_GET_NODE_DATA(p_st_node);
                if (p_nids_handle == NULL || p_nids_handle->p_dev == NULL)
                    break;
                
                p_dev_one = p_nids_handle->p_dev;
                i_ret_fun = pthread_create(&g_thread_id_pcap[i_loop++], NULL, __frame_daq, (void *)p_dev_one);
                if(i_ret_fun)
                {
                    FRLOG_ERROR_DETAIL("pthread_create __frdbg_report_ssl err");
                    i_ret = FR_FAIL;
                    goto END;
                }
                if (i_loop >= APM_DEV_MAX)
                {
                    FRLOG_ERROR_DETAIL("input dev error, [%s]", p_dev);
                    i_ret = FR_FAIL;
                    goto END;
                }
                
                p_st_node = FRLIST_NEXT_NODE(p_st_node);
            }
            g_i_pcap_threads = i_loop;
        }
        int i = 0;
        for (i=0;i<g_i_nids_threads;i++)
        {
            i_ret_fun = pthread_create(&g_thread_nids[i], NULL, __frame_nids, (void *)&g_st_nids_ip_tcp_stream[i]);
            if(i_ret_fun)
            {
                FRLOG_ERROR_DETAIL("pthread_create __frdbg_report_ssl err");
                i_ret = FR_FAIL;
                goto END;
            }
        }
    } while (0);


    //数据包调试模式下,等待数据包
    while(g_i_flag_run == 1)
    {
        sleep(1);
    }
    
    event_base_loopbreak(g_p_st_ebase);
    #ifdef FRDBG_CT_PRINT
    //frct_expect_output(NULL);
    //frct_hash_output(NULL);
    #endif

END:
    g_i_flag_run = 0;
    sleep(1);

    __frame_destory();
    FRLOG_INFO("apm analyse end...");
    printf("apm analyse end...\n");
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  显示命令帮助
*  ARGS     :  p_pgname      (运行查询名称)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __usage(char *p_pgname)
{
    printf("version: %s\n", g_arr_frame_version);
    printf("Usage: %s [OPTION]... \n", p_pgname);
    printf("param info\n");
    printf("\t-d 测试用pcap文件\n");
    printf("\t-a 程序启动等待数据包进入时间(秒),默认 3sec(范围 0-60). eg. -a 3\n");
    printf("\t-t 使用pcap文件时,程序等待退出时间(秒),默认 5sec(范围 0-60). eg. -t 5\n");
    printf("\t-n 不进行checksum检查.\n");
    printf("\t-u 使用pcap文件时,更改获取数据包时间为系统时间.\n");
    //printf("\t-m 设置主框架内存大小(M).(default 100Mbyte)(eg. -m 200)\n");
    printf("\n");

    printf("\t-i 网卡设备名 (eg. -i eth2). (default eth0)\n");
    printf("\t--cap_type (抓包类型,文件读取时无效), 0:pcap 1:afpacket, 默认 pcap eg. --cap_type 1\n");
    printf("\t--snaplen (抓取数据包长度,数据包文件获取时无效. 单位byte, eg. --snaplen 16384), 最大65535, 默认 16384\n");
    printf("\t--ring_size (ring buffer size 单位M, eg. --ring_size 128). 范围 4(4M) - 2048(2048M)\n");
    printf("\n");

    printf("\t--report_base64    上报web服务器的数据base64后出力文件\n");
    printf("\t--report_writefile 上报数据文件输出\n");
    printf("\t--report_console   上报l7数据屏幕出力\n");
    printf("\t--report_testtools 数据发送测试工具\n");
    printf("\n");

    printf("\t--drop_timestamp_incorrect   删除时间不正确的数据包\n");
    printf("\t--enable_stat_tcp   收集上报tcp统计信息(默认不开启)\n");
    printf("\n");

    printf("\t-h/--help help.\n");

    return;
}

/*******************************************************************************
*  FUNC     :  nids的log函数
*  ARGS     :
*  RTN      :
*  NOTE     :  屏蔽nids的log出力
*******************************************************************************/
FR_STATIC void __frame_nids_syslog(int type, int errnum, struct ip *iph, void *data)
{
    return;
}

/*******************************************************************************
*  FUNC     :  协议解析环境设定
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frame_init_env(void)
{
    int i_ret_fun =0;
    //int i_len=0;
    //char *p_cmd = NULL;
    //const char *p_file="/*";
    DIR *p_dir=NULL;

    //创建工作目录
    p_dir = opendir(APM_DIR_WORK_TEMP);
    if( p_dir == NULL)
    {
        i_ret_fun = mkdir(APM_DIR_WORK_TEMP, 0775);
        if(i_ret_fun != 0)
            return FR_FAIL;
    }
    else
        closedir(p_dir);

    //清理工作目录下内容
//    i_len = strlen(APM_DIR_WORK_TEMP) + strlen(p_file) + 30;
//    p_cmd = (char *) frmalloc(i_len);
//    if(p_cmd == NULL)
//        return FR_FAIL;
//    snprintf(p_cmd, i_len, "%s -rf %s%s", FR_CMD_RM, APM_DIR_WORK_TEMP, p_file);
//    system(p_cmd);
//    frfree(p_cmd);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  获取主版本号
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
const char *frame_version(void)
{
    return g_arr_frame_version;
}

/*******************************************************************************
*  FUNC     :  apm主程序
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
int main( int argc, char *argv[] )
{
    int i_flag_param=0, i_flag_chksum = FR_YES,  i_flag_exit=FR_NO, i_loop;
    char *p_dumpfile=NULL;
    int i_dumpfile_times=1, i_ring_size=0, i_snaplen = 0, i_cap_type=0;
    unsigned int ui_mempool_size = 1024*1024*100;//100 Mbyte
    int i_ret_fun=0;
    const char *p_dev;
    const char *p_short_opts = "a:d:f:m:i:t:nhu";
    struct option st_long_opts[] = { {"help", 0, NULL, 'H'},
                                     {"drop_timestamp_incorrect", 0, NULL, 'A'},
                                     {"enable_stat_tcp", 0, NULL, 'b'},
                                     {"cap_type", 1, NULL, 'D'},
                                     {"snaplen", 1, NULL, 'N'},
                                     {"ring_size", 1, NULL, 'S'},
                                     {"report_base64", 0, NULL, 'B'},
                                     {"report_writefile", 0, NULL, 'W'},
                                     {"report_console", 0, NULL, 'C'},
                                     {"report_testtools", 0, NULL, 'T'},
                                     {NULL, 0, NULL, 0} };
    Frreport_params st_report_params={0,0,0,0};
    char arr_report_params[128];

    //初始化版本
    frversion_set(g_arr_frame_version, sizeof(g_arr_frame_version), FRAME_MINOR);

    p_dev="eth0";
    //获取程序参数
    while((i_flag_param=getopt_long(argc, argv, p_short_opts, st_long_opts, NULL) )!=-1)
    {
        switch(i_flag_param)
        {
            case 'a': //程序启动等待数据包进入时间(秒)
                g_i_pcap_wait = atoi(optarg);
                if(g_i_pcap_wait <= 0 || g_i_pcap_wait> 60)
                    g_i_pcap_wait = 3;
                break;
            case 'A': //测试用pcap文件
              //frdbg("option A:[%s]\n",optarg);
              g_flag_drop_timestamp_incorrect = 1;
              break;
            case 'b': //tcp统计上报控制
                g_i_enable_stat_tcp = 1;
              break;
            case 'd': //测试用pcap文件
              //frdbg("option d:[%s]\n",optarg);
              p_dumpfile = optarg;
              break;
            case 'D': //cap_type 0:pcap; 1:afpacket
                i_cap_type = atoi(optarg);
              if(i_cap_type < 0 || i_cap_type > 1)
                  i_cap_type = 0;
              break;
            case 'H':
            case 'h':
              __usage(argv[0]);
              i_flag_exit = FR_YES;
              break;
            case 'i': //网卡设备名
              p_dev = optarg;
              break;
            case 'm': //缓存池空间大小
                ui_mempool_size = atoi(optarg);
                if(ui_mempool_size < 10) //10Mbyte
                    ui_mempool_size = 100;//100 Mbyte
                ui_mempool_size = ui_mempool_size * 1024 * 1024;
                break;
            case 'n': //不进行checksum检查
              i_flag_chksum = FR_NO;
              break;
            case 't': //使用pcap文件时,程序等待退出时间(秒)
                g_i_exit_wait = atoi(optarg);
                if(g_i_exit_wait < 0 || g_i_exit_wait> 60)
                    g_i_exit_wait = 5;
                break;
            case 'u': //使用pcap文件时,更改获取数据包时间
                g_i_use_system_time = 1;
                break;
            case 'N': //snaplen 数据包长度
                i_snaplen = atoi(optarg);
              if(i_snaplen < 0)
                  i_snaplen = 0;
              else if(i_snaplen > 65535)
                  i_snaplen = 65535;
              break;
            case 'S': //ring buffer size
              i_ring_size = atoi(optarg);
              if(i_ring_size < 0)
                  i_ring_size = 0;
              else if(i_ring_size < 4 || i_ring_size > 2048) //< 4M || > 512M
                  i_ring_size = 128; //128M
              break;
            case 'C':
                st_report_params.i_console = 1;
              break;
            case 'B':
                st_report_params.i_base64 = 1;
              break;
            case 'T':
                st_report_params.i_totools = 1;
              break;
            case 'W':
                st_report_params.i_tofile = 1;
              break;
            default:
              break;
        }
        //frdbg("optopt+%c\n",optopt);
    }

    if(i_flag_exit == FR_YES)
        return 0;
    if(i_ring_size > 0 )
        nids_params.ring_size = i_ring_size;
    if(i_snaplen > 0 )
        nids_params.snaplen = i_snaplen;
    if(p_dumpfile == NULL)
        nids_params.i_module_type = i_cap_type;
    if(p_dumpfile)
        g_flag_dump_file = 1;

    //设置report选项
    snprintf(arr_report_params, sizeof(arr_report_params), "console=%d testtools=%d writefile=%d base64=%d"
                , st_report_params.i_console, st_report_params.i_totools, st_report_params.i_tofile, st_report_params.i_base64);

    //nids log不出力
    nids_params.syslog = __frame_nids_syslog;

    //更改当前程序的工作目录
    {
        unsigned int ui_buff_size = 1000;
        char *p_buff = (char *)malloc(ui_buff_size);
        if(p_buff == NULL)
        {
            frwarn("main malloc err\n");
            return 0;
        }
        //memset(p_buff, '\0', ui_buff_size);
        i_ret_fun = frget_absdir(argv[0], p_buff, ui_buff_size-1);
        if(i_ret_fun == FR_SUCC)
            chdir(p_buff);
        free(p_buff);
    }

    //配置内存
    g_p_memstat = fr_slab_init((&g_st_mem_env), "framework");
    if(g_p_memstat == NULL)
    {
        FRLOG_ERROR_DETAIL("fr_slab_init err");
        frwarn("fr_slab_init err\n");
        return 0;
    }

    i_ret_fun = frlog_open(APM_CFG_FILENAME_ZLOG, "apm_framework");
    if (i_ret_fun)
    {
        frwarn("log_open failed\n");
        fr_slab_destroy();
        return 1;
    }

    //配置环境
    i_ret_fun = __frame_init_env();
    if (i_ret_fun != FR_SUCC)
    {
        frwarn("init env err\n");
        FRLOG_ERROR_DETAIL("init env err");
        frlog_close();
        fr_slab_destroy();
        return 1;
    }

    //获取配置信息
    if(p_dumpfile)
        frame_params_get(FR_YES);
    else
        frame_params_get(FR_NO);
    frame_params_output();
    g_i_do_task_cnt = st_apm_params.ui_do_task_cnt;
    g_i_nids_threads = st_apm_params.ui_nids_cnt;

    //配置nids环境
    FRLOG_INFO("p_dumpfile=[%s] dev=[%s] nids: ring_size=%dM snaplen=%d cap_type=%d(0:pcap 1:afpacket) drop_timestamp_incorrect=%d(0:none 1:drop)"
              , p_dumpfile, nids_params.device, nids_params.ring_size, nids_params.snaplen, nids_params.i_module_type
              , g_flag_drop_timestamp_incorrect);
    if(p_dumpfile)
        nids_params.filename = p_dumpfile;
    if(i_flag_chksum == FR_NO)
        __frame_chg_chksum(FR_NO);
    nids_params.scan_num_hosts = 0;

    //设置nids里面删除udp重复包的默认值
    nids_params.n_udp_streams = st_apm_params.i_nids_udp_hash_size;
    nids_params.i_udp_repeat_time = st_apm_params.i_nids_udp_repeat_timeout;
    nids_params.i_udp_cache_time = st_apm_params.i_nids_udp_cache_time;

    for(i_loop=0; i_loop < APM_STAT_CNT; i_loop++)
        g_thread_id_stat[i_loop]=0;

    for(i_loop=0; i_loop < APM_DEV_MAX; i_loop++)
        g_thread_id_pcap[i_loop]=0;
    for(i_loop=0; i_loop < APM_DEV_MAX; i_loop++)
        g_thread_nids[i_loop]=0;
    xmlInitParser();
    //xmlKeepBlanksDefault (0);

    //防止统计函数第1次计算时，由于时间片过小，计算误差比较大
    sleep(1);
    __frame_do_analyser(p_dev, i_dumpfile_times, arr_report_params);

    xmlCleanupParser();
    frlog_close();
    fr_slab_destroy();
    return 0;
}
